React Dynamic Table

This is a ReactJS expansion to my Responsive HTML Tables.

index.js

import React from 'react';
import { Table } from '../components/elements/Table';

export default function Home() {

  return (<>
    <h1>Home</h1>

    <Table
      caption='Pokemon'
      route='/pokemon'
      headers={[
        'name',
        'type',
        'height',
        'weight',
        'baseExp',
        'link'
      ]}
      cells={[
        {
          name: 'pikachu',
          type: 'electric',
          height: '0.4',
          weight: '6.0',
          baseExp: '112',
        },
        {
          name: 'Charmander',
          type: 'Fire',
          height: '0.6',
          weight: '8.5',
          baseExp: '62',
        },
      ]}
    />

  </>)
}

If the table links to other data, then It dynamically adds a link in one of the chosen cells named link url uri a anchor account ect.

Table.js

import Link from 'next/link';
import React, { useState } from 'react';
import styled from 'styled-components';

interface TableProps {
  caption: string;
  cells: object[];
  headers?: string[];
  route?: string;
}

export function Table({ caption, cells, headers, route }: TableProps) {

  const [keys, setKeys] = useState<any>(headers)
  const linkterms = ['link', 'url', 'uri', 'a', 'anchor', 'account',]

  // ? if u want to automatically grab keys from object
  
  // const [keys, setKeys] = useState<any>(Object.keys(cells[0]))
  
  // // Extract the keys from the first item in the data array
  // useState(() => {
  //   if (cells.length > 0) {
  //     setKeys(Object.keys(cells[0]))
  //   }
  // }, [cells]);

  return (
    <div role="region" aria-labelledby="Cap" tabIndex={0}>
      <StyledTable role="table">
        <caption role="caption"> {caption} </caption>

        <thead role="rowgroup">
          <tr role="row">
            {keys.map((key: string) => (
              <th key={key} role="columnheader">{key}</th>
            ))}
          </tr>
        </thead>

        <tbody role="rowgroup">
          {cells.map((item: any, index: number) => (
            <tr key={index} role="row">
              {keys.map((key: string) => (
                <td key={key} data-cell={key} role="cell">
                  {route && linkterms.includes(key) ? (
                    <Link href={`${route}/${item['id']}`}> {key} </Link>
                  ) : (
                    item[key]
                  )}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </StyledTable>
    </div>
  );
}

const StyledTable = styled.table`
  background-color: #909c9f;
  color: white;
  border-collapse: collapse;
  padding: 1rem;

  th, td, caption {
    padding: .1rem 1rem;
  }

  caption{
    background-color: #479282;
    font-size: 1.5rem;
    font-weight: 700;
    text-transform: uppercase;
  }

  th {
    text-align: left;
    background-color: hsl( 0 0% 0% / 0.5);
    border-right: solid 1px black;
  }
  tr:nth-of-type(2n) {
    background-color: hsl( 0 0% 0% / 0.1);
  }

  @media (max-width: 650px) {

    th{
      display: none;
    }

    td{
      display: grid;
      grid-template-columns: 15ch auto;
      gap: .5rem;
      padding: 0.5rem 1rem;
    }

    td:first-child{
      padding-top: 2rem;
    }
    td:last-child{
      padding-bottom: 2rem;
    }

    td::before {
      content: attr(data-cell) ': ';
      font-weight: 700;
      text-transform: capitalize;
    }
  }
`

Credit